package com.nsyue.auth.config.resources;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.security.oauth2.provider.authentication.TokenExtractor;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * 用于从请求头中获取token，解析身份和resourceIds等，
 * 传入下一步的 {@link org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter}，
 * 验证是否有该客户端的权限
 *
 * @author laixm
 */
@Slf4j
public class CustomTokenExtractor implements TokenExtractor {

    private final String headerName;

    public CustomTokenExtractor(String headerName) {
        this.headerName = headerName;
    }

    @Override
    public Authentication extract(HttpServletRequest request) {
        String tokenValue = extractHeaderToken(request);
        if (tokenValue != null) {
            return new PreAuthenticatedAuthenticationToken(tokenValue, "");
        }
        return null;
    }

    /*
    * 可以以"Bearer"开头，不区分大小写
    */
    protected String extractHeaderToken(HttpServletRequest request) {
        Enumeration<String> headers = request.getHeaders(headerName);
        while (headers.hasMoreElements()) {
            String authHeaderValue = headers.nextElement();
            if (StrUtil.isNotBlank(authHeaderValue)) {
                if ((authHeaderValue.toLowerCase().startsWith(OAuth2AccessToken.BEARER_TYPE.toLowerCase()))) {
                    authHeaderValue = authHeaderValue.substring(OAuth2AccessToken.BEARER_TYPE.length()).trim();
                }
                request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, OAuth2AccessToken.BEARER_TYPE);
                return authHeaderValue;
            }
        }
        return null;
    }
}
